package com.tongtong.stsuserapi.service.base.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tongtong.stscommon.enumration.CollectionCodeState;
import com.tongtong.stscommon.enumration.FileType;
import com.tongtong.stscommon.enumration.Message;
import com.tongtong.stscommon.enumration.Status;
import com.tongtong.stscommon.exception.*;
import com.tongtong.stscommon.message.STSMessage;
import com.tongtong.stscommon.message.STSSuccessMessage;
import com.tongtong.stscommon.utils.RedisCache;
import com.tongtong.stscommon.utils.checker.ObjectChecker;
import com.tongtong.stscommon.utils.checker.cellphoneChecker;
import com.tongtong.stscommon.utils.checker.emailChecker;
import com.tongtong.stsuserapi.dao.CollectionCodeDao;
import com.tongtong.stsuserapi.dao.UserDao;
import com.tongtong.stsuserapi.pojo.CollectionCode;
import com.tongtong.stsuserapi.pojo.User;
import com.tongtong.stsuserapi.service.base.UserService;
import com.tongtong.stsuserapi.service.qiniu.QiniuService;
import com.tongtong.stsuserapi.service.register.CaptchaService;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 用户业务层
 */
@Service
public class UserServiceImpl implements UserService {

	@Autowired
	UserDao userDao;

	@Autowired
	PasswordEncoder passwordEncoder;

	@Autowired
	QiniuService qiniuService;

	@Autowired
	RedisCache redisCache;

	@Autowired
	CaptchaService captchaService;

	@Autowired
	AuthenticationManager authenticationManager;

	@Autowired
	CollectionCodeDao collectionCodeDao;

	@Override
	public STSMessage<User> getInfoById(Long id){
		User user = userDao.selectById(id);
		ObjectChecker.ObjectsFromDBNullCheck(user);
		return STSSuccessMessage.from(user);
	}

	@Override
	public STSMessage addUser(User user) {

		ObjectChecker.ObjectsFromHTTPNullCheck(user);

		try {
			userDao.insert(user);
		} catch (Exception e) {
			throw new STSResourcesOperationException(Status.AddResourcesError, e.getMessage());
		}

		Map<String,String> map = new HashMap<>();
		map.put("userid",user.getId().toString());

		return STSSuccessMessage.from(map);
	}

	@Override
	public STSMessage updateUserById(Long id, User user) {

		ObjectChecker.ObjectsFromHTTPNullCheck(user);

		// 阻止更新密码和手机号
		if(!StringUtil.isNullOrEmpty(user.getPassword()))
			user.setPassword(null);
		if(!StringUtil.isNullOrEmpty(user.getPhone()))
			user.setPhone(null);

		// 检测用户名重复
		if(!StringUtil.isNullOrEmpty(user.getUsername())
				&& !user.getUsername().equals(userDao.selectById(id).getUsername())
				&& checkUsernameExits(user.getUsername())) {
				throw new STSResourcesOperationException(Status.UpdateResourcesError,Message.UsernameUsed);
		}

		// 检测邮箱格式
		if(!StringUtil.isNullOrEmpty(user.getEmail())
				&& emailChecker.isInvalidFormat(user.getEmail())) {
			throw new STSResourcesOperationException(Status.UpdateResourcesError,Message.EmailInvalid);
		}

		user.setId(id);

		try {
			userDao.updateById(user);
		} catch (Exception e) {
			throw new STSResourcesOperationException(Status.UpdateResourcesError, e.getMessage());
		}

		return STSSuccessMessage.from(Status.OK, Message.OK);
	}

	@Override
	public STSMessage updateHeadById(Long id, MultipartFile file) throws Exception {
		// 获取指定用户
		User user = userDao.selectById(id);
		ObjectChecker.ObjectsFromDBNullCheck(user);

		// 删除原图片
		String pre_url = user.getHeadUrl();
		if(!StringUtil.isNullOrEmpty(pre_url)) {
			qiniuService.Delete(pre_url);
		}

		// 更新图片
		String url = qiniuService.Upload(file, FileType.AvatarIMG).get("url").toString();
		user.setHeadUrl(url);

		try {
			userDao.updateById(user);
		} catch (Exception e) {
			throw new STSResourcesOperationException(Status.UpdateResourcesError,e.getMessage());
		}

		Map<String,String> map = new HashMap<>();
		map.put("url",url);

		return STSSuccessMessage.from(map);
	}

	@Override
	public STSMessage uploadCollectionCode(Long id, MultipartFile file) throws Exception {

		LambdaQueryWrapper<CollectionCode> lqw = new LambdaQueryWrapper<>();
		lqw.eq(CollectionCode::getUserId, id);
		CollectionCode collectionCode = collectionCodeDao.selectOne(lqw);

		Map<String,String> map = new HashMap<>();

		if(Objects.isNull(collectionCode)) {
			collectionCode = new CollectionCode();
			collectionCode.setUserId(id);

			// 上传图片
			String url = qiniuService.Upload(file, FileType.CollectionCodeIMG).get("url").toString();
			collectionCode.setCodeUrl(url);
			collectionCode.setCodeState(CollectionCodeState.ToBeAudited);
			collectionCode.setApplyTime(new Timestamp(System.currentTimeMillis()));

			try {
				collectionCodeDao.insert(collectionCode);
			} catch (Exception e) {
				throw new STSResourcesOperationException(Status.AddResourcesError,e.getMessage());
			}

			map.put("url",url);

		} else {
			// 删除原图片
			String pre_url = collectionCode.getCodeUrl();
			qiniuService.Delete(pre_url);

			// 更新图片
			String url = qiniuService.Upload(file, FileType.CollectionCodeIMG).get("url").toString();
			collectionCode.setCodeUrl(url);
			collectionCode.setCodeState(CollectionCodeState.ToBeAudited);
			collectionCode.setApplyTime(new Timestamp(System.currentTimeMillis()));

			try {
				collectionCodeDao.updateById(collectionCode);
			} catch (Exception e) {
				throw new STSResourcesOperationException(Status.UpdateResourcesError,e.getMessage());
			}

			map.put("url",url);

		}


		return STSSuccessMessage.from(map);
	}

	@Override
	public STSMessage deleteUserById(Long id) {

		int affectRows;
		try {
			affectRows = userDao.deleteById(id);
		} catch (Exception e) {
			throw new STSResourcesOperationException(Status.DeleteResourcesError,e.getMessage());
		}
		if(affectRows<1)
			throw new STSResourcesOperationException(Status.DeleteResourcesError,Message.ObjectCanNotFound);

		return STSSuccessMessage.from(Status.OK,Message.OK);
	}

	@Override
	public STSMessage updatePasswordById(Long userid, String oldPassword, String newPassword) {

		// 密码校验
		User user = userDao.selectById(userid);
		ObjectChecker.ObjectsFromDBNullCheck(user);

		// AuthenticationManager authenticate进行用户认证
		UsernamePasswordAuthenticationToken authenticationToken =
				new UsernamePasswordAuthenticationToken(user.getPhone(),oldPassword);
		Authentication authenticate = authenticationManager.authenticate(authenticationToken);

		// 如果认证不通过，给出对应的提示
		if(Objects.isNull(authenticate)) {
			throw new STSAuthenticationException(Status.AuthenticationError,Message.PasswordError);
		}

		user.setPassword(passwordEncoder.encode(newPassword));
		userDao.updateById(user);

		// 注销登录
		redisCache.deleteObject("login:"+userid);

		return STSSuccessMessage.from(Status.OK,Message.OK);
	}

	@Override
	public STSMessage retrievePassword(String phone, String captcha, String password) {
		// 检测手机号格式
		if(cellphoneChecker.isInvalidFormat(phone)) {
			throw new STSPhoneNumberValidationException(Status.PhoneNumberIllegal,Message.PhoneNumberInvalid);
		}
		// 检测手机号是否已注册
		if(!checkPhoneNumberExits(phone)) {
			throw new STSRegisterException(Status.AuthenticationError,Message.ObjectCanNotFound);
		}

		// 验证码核验 若有错误会抛出异常
		captchaService.verifyCaptcha(phone,captcha);

		// 核验通过 重置密码
		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
		lqw.eq(User::getPhone,phone);
		User user = userDao.selectOne(lqw);
		user.setPassword(passwordEncoder.encode(password));

		try {
			userDao.updateById(user);
		} catch (Exception e) {
			throw new STSResourcesOperationException(Status.UpdateResourcesError,e.getMessage());
		}

		return STSSuccessMessage.from(Status.OK,Message.OK);
	}

	@Override
	public STSMessage updatePhoneById(Long id, String oldPhone, String newPhone, String captcha) {
		// 检测手机号格式
		if(cellphoneChecker.isInvalidFormat(oldPhone) || cellphoneChecker.isInvalidFormat(newPhone)) {
			throw new STSPhoneNumberValidationException(Status.PhoneNumberIllegal,Message.PhoneNumberInvalid);
		}
		// 检测手机号是否已注册
		if(checkPhoneNumberExits(newPhone)) {
			throw new STSRegisterException(Status.PhoneNumberRegistered,Message.PhoneNumberRegistered);
		}

		// 验证码核验 若有错误会抛出异常
		captchaService.verifyCaptcha(oldPhone,captcha);

		// 核验通过 重置手机号
		User user = userDao.selectById(id);
		user.setPhone(newPhone);

		try {
			userDao.updateById(user);
		} catch (Exception e) {
			throw new STSResourcesOperationException(Status.UpdateResourcesError,e.getMessage());
		}

		// 注销登录
		redisCache.deleteObject("login:"+id);

		return STSSuccessMessage.from(Status.OK,Message.OK);
	}

	@Override
	public STSMessage dynamicSearchByPage(User user, Integer page, Integer pageSize) {

		ObjectChecker.ObjectsFromHTTPNullCheck(user);

		HashMap<String, Object> map = new HashMap<>();

		List<User> list = userDao.dynamicSelect(user,page,pageSize);
		Long len = userDao.dynamicSelectCount(user);

		map.put("list",list);
		map.put("len",len);

		return STSSuccessMessage.from(map);
	}

	@Override
	public boolean checkUsernameExits(String username) {

		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.eq(User::getUsername,username);

		List<User> user = userDao.selectList(lqw); // 查询指定用户名的用户信息

		return !user.isEmpty();
	}

	@Override
	public boolean checkPhoneNumberExits(String phone) {

		LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
		lqw.eq(User::getPhone,phone);

		List<User> user = userDao.selectList(lqw); // 查询指定用户名的用户信息

		return !user.isEmpty();
	}
}
